package com.tjkcht.midware.reader;

import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import com.shhic.itsed.mws.deviceintf.IReaderResultCallback;
import com.shhic.itsed.mws.deviceintf.RawTagOperationResult;
import com.shhic.itsed.mws.deviceintf.ReaderCommand;
import com.shhic.itsed.mws.deviceintf.ReaderLinkStatusEnum;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;

// TODO: Auto-generated Javadoc
/**
 * 阅读器抽象类.
 */
public abstract class Reader implements IReader {

	/** The host. */
	protected String readerIp;

	/** The port. */
	protected int port;

	/** 配置信息. */
	protected Map<String, String> initParams;

	/** 断链重连次数. */
	protected int reconnectTime = 0;

	/** The bootstrap. */
	protected Bootstrap bootstrap;

	/** The channel. */
	protected Channel channel;

	/** The status. */
	protected ReaderLinkStatusEnum status = ReaderLinkStatusEnum.UNCONNECTED;

	/** The cmd. */
	protected ReaderCommand cmd;

	/** The send out. */
	protected boolean sendOut = false;

	/** The result callback. */
	protected IReaderResultCallback resultCallback;

	/** The log. */
	protected Logger log = Logger.getLogger("Reader");

	/**
	 * Instantiates a new reader.
	 *
	 * @param bootstrap
	 *            the bootstrap
	 * @param readerIp
	 *            the reader ip
	 * @param port
	 *            the port
	 */
	public Reader(Bootstrap bootstrap, String readerIp, int port) {
		this.readerIp = readerIp;
		this.port = port;
		this.bootstrap = bootstrap;
	}

	public Reader(Bootstrap bootstrap, String readerIp, int port, Map<String, String> config) {
		super();
		this.readerIp = readerIp;
		this.port = port;
		this.initParams = config;
		this.bootstrap = bootstrap;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tjkcht.midware.reader.IReader#connect()
	 */
	public synchronized void connect() throws InterruptedException {
		if (channel != null && channel.isActive()) {
			return;
		}
		setStatus(ReaderLinkStatusEnum.CONNECTING);
		ChannelFuture future = bootstrap.connect(readerIp, port);
		future.addListener(new ChannelFutureListener() {
			public void operationComplete(ChannelFuture futureListener) throws Exception {
				if (futureListener.isSuccess()) {
					channel = futureListener.channel();
					reconnectTime = 0;
					log.info("Connect to server " + readerIp + " successfully!");
					sendOut = false;
					reWrite();
				} else {
					reconnectTime++;
					int delayTime = 10;
					if (reconnectTime < 4) {
						delayTime *= reconnectTime;
					} else {
						delayTime = 120;
					}
					futureListener.channel().eventLoop().schedule(new Runnable() {
						public void run() {
							try {
								connect();
							} catch (InterruptedException e) {
								log.severe(e.getMessage());
							}
						}
					}, delayTime, TimeUnit.SECONDS);
					setStatus(ReaderLinkStatusEnum.UNCONNECTED);
					warnBack("Failed to connect to server " + readerIp + " ,try connect after " + delayTime + "s");
				}
			}
		});
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tjkcht.midware.reader.IReader#read()
	 */
	public void read(byte[] msgBytes) {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tjkcht.midware.reader.IReader#disconnect()
	 */
	public synchronized void disconnect() {
		if (null != channel) {
//			try {
				channel.disconnect();
				channel.close();
				channel = null;
//			} catch (InterruptedException e) {
//				log.warning(e.getMessage());
//			}
		
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tjkcht.midware.reader.IReader#setStatus(com.shhic.itsed.mws.
	 * deviceintf.ReaderLinkStatusEnum)
	 */
	public synchronized void setStatus(ReaderLinkStatusEnum status) {
		this.status = status;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tjkcht.midware.reader.IReader#getStatus()
	 */
	public ReaderLinkStatusEnum getStatus() {
		return status;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tjkcht.midware.reader.IReader#write(com.shhic.itsed.mws.deviceintf.
	 * ReaderCommand, com.shhic.itsed.mws.deviceintf.IReaderResultCallback)
	 */
	public synchronized void write(byte[] msgBytes) {
		if (null == channel) {
			warnBack("link not established");
			return;
		}
		ByteBuf outBuf = Unpooled.buffer(msgBytes.length + 4);
		outBuf.writeInt(msgBytes.length);
		outBuf.writeBytes(msgBytes);
		ChannelFuture future = channel.writeAndFlush(outBuf);
//		try {
//			future.await();
//			if (!future.isSuccess()) {
//				warnBack("Send message failure!");
//			}
//		} catch (InterruptedException e) {
//			warnBack(e.getMessage());
//		}
	}

	/**
	 * Callback.
	 *
	 * @param result
	 *            the result
	 */
	public synchronized void callback(RawTagOperationResult result) {
		// 空闲状态，即执行周期内天线下没有标签
		if (null == result) {
			resultCallback.onIdle();
		} else {
			resultCallback.onResult(result);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tjkcht.midware.reader.IReader#warnBack(java.lang.String)
	 */
	public synchronized void warnBack(String warnMsg) {
		if (null != resultCallback) {
			resultCallback.onError(status, warnMsg);
		}
		log.warning(readerIp + ":" + warnMsg);
	}

	public Map<String, String> getInitParams() {
		return initParams;
	}

	public synchronized void setInitParams(Map<String, String> initParams) {
		this.initParams = initParams;
	}
}
